package xray

import (
	"encoding/json"
	"fmt"
	"gitee.com/gam6it/SecToolkit/utils/http2"
	"time"
)

/**
X-Ray主文件，获取Xray的Client
*/

const (
	EngineName     = "X-Ray"
	StatusFinished = "FINISHED"
	StatusProcess  = "WORKING"
)

type Client struct {
	ProjectId int
	URI       string
	Token     string
	Engines   []Engine
	TimeOut   time.Duration
}

type Engine struct {
	Id   string
	Addr string
}

// NewClient 创建一个Xray客户端
// url: url地址， token token, projectId 项目id, engineIds 引擎id, timeout 超时时间
func NewClient(url string, token string, projectId int, engineIds []string, timeout time.Duration) *Client {
	var engines []Engine
	for _, engineId := range engineIds {
		engines = append(engines, Engine{
			Id:   engineId,
			Addr: "",
		})
	}
	var client = Client{
		ProjectId: projectId,
		URI:       url,
		Token:     token,
		Engines:   engines,
		TimeOut:   timeout,
	}
	return &client
}

func (c *Client) Template(id int) (*Template, error) {
	return newTemplate(c, id)
}

func (c *Client) Plan(id int) (*Plan, error) {
	return newPlan(c, id)
}

func (c *Client) XProcess(id int) (*XProcess, error) {
	return newXProcess(c, id)
}

type Resp struct {
	Err       string      `json:"err,omitempty"`
	Msg       string      `json:"msg"`
	Data      interface{} `json:"data,omitempty"`
	ExtraData interface{} `json:"extra_data,omitempty"`
}

func request(method string, api string, token string, result any, options ...func(*http2.Req)) error {
	var err error
	var resp Resp
	var opts = []func(req *http2.Req){
		http2.ContentType(http2.ContentTypeJson),
		http2.AddHeader("Token", token),
	}
	for _, opt := range options {
		opts = append(opts, opt)
	}
	err = http2.RequestJsonUnmarshal(method, api, &resp, opts...)
	if err == nil && resp.Err == "" && resp.Msg == "OK" {
		if result == nil { // 需要返回值
			return nil
		} else { // 有返回值的
			b, err := json.Marshal(resp.Data)
			if err != nil {
				return err
			}
			return json.Unmarshal(b, result)
		}
	}
	return fmt.Errorf("[%s]API[%s]失败，错误原因:%v,返回中Err:%s,返回中Msg:%s,返回中ExtraData:%v", method, api, err, resp.Err, resp.Msg, resp.ExtraData)
}
